package routeFunctions;

import java.util.ArrayList;

import XMLread.Building;
import XMLread.Exit;
import XMLread.Floor;
import XMLread.Hallway;
import XMLread.Intersection;
import XMLread.Space;
import XMLread.Stairwell;

/**
 * 
 * @author Chris
 *
 */
public class Route {
	private ArrayList<Object> traversed;
	private ArrayList<Object> directions;
	private Route finalRoute = null;
	boolean routeIsSet = false;

	/**
	 * Default constructor for class Route
	 * initializes traversed and directions to new ArrayLists
	 */
	public Route(){
		traversed = new ArrayList<Object>();
		directions = new ArrayList<Object>();
		
	}
	
	public Route(ArrayList<Object> traversed, ArrayList<Object> directions){
		this.traversed = traversed;
		this.directions = directions;
	}
	
	public boolean finalRouteSet(){
		return routeIsSet;
	}
	
	public void setFinalRoute(Route r){
		if(routeIsSet){
			if(finalRoute.getTraversedSize()<= r.getTraversedSize())
				return;
			finalRoute = r;
		}else{
			finalRoute = r;
		}
	}
	
	public Route getFinalRoute(){
		return finalRoute;
	}

	public void addTraversed(Object o){
		traversed.add(o);
	}

	public int getTraversedSize(){
		return traversed.size();
	}

	public boolean hasBeenTraversed(Object o){
		return traversed.contains(o);
	}

	public void addDirection(Object d){
		directions.add(d);
	}

	public ArrayList<Object> getDirections(){
		return directions;
	}

	public ArrayList<Object> getTraversed(){
		return traversed;
	}

	public void setTraversed(ArrayList<Object> traversed2) {
		traversed = traversed2;
	}

	public void setDirections(ArrayList<Object> traversed2) {
		directions = traversed2;
	}

	public Route getRoute(Object start, Building building, Route route){
		//we are at our ending location so return our route
		if(start instanceof Exit){
			route.addDirection(start);
			route.addTraversed(start);
			return route;
		}
		//we have already passed the start location we went in loop not most efficient path return null
		if(route.hasBeenTraversed(start))
			return null;



		//add our start location to list of traversed entities so we don't traverse it again
		route.addTraversed(start);

		ArrayList<Object> entities = new ArrayList<Object>();
		int startIndex = 0;

		//start is a Space
		if(start instanceof Space){


			boolean foundStart = false;
			for(Floor f : building.getFloors()){
				for(Hallway h : f.getHallways()){
					if(h.getEntities().contains(start)){
						entities = h.getEntities();
						startIndex = entities.indexOf(start);
						foundStart = true;
						break;
					}
				}
				if(foundStart)
					break;
			}

			//we are at the start of the hallway
			if(startIndex == 0)
				return getRoute(entities.get(1), building, route);

			//we are the end of a hallway
			else if(startIndex == entities.size()-1)
				return getRoute(entities.get(startIndex-1), building, route);

			//we are in the middle of a hallway
			else{
				
				Route tempRoute = getRoute(entities.get(startIndex+1), building, route);
				
				Route tempRoute2 = getRoute(entities.get(startIndex-1), building, route);
				
				if(tempRoute2 != null && tempRoute != null && tempRoute.getTraversedSize()< tempRoute2.getTraversedSize()){
					return tempRoute;
				}
				if(tempRoute2 != null && tempRoute != null && tempRoute.getTraversedSize()>= tempRoute2.getTraversedSize()){
					return tempRoute2;
				}
				if(tempRoute == null && tempRoute2 != null){
					return tempRoute2;
				}
				if(tempRoute != null && tempRoute2 == null){
					return tempRoute;
				}
				else{
					return null;
				}
			}
		}




		//start location is an Intersection
		if(start instanceof Intersection){
			route.addDirection(start);

			//Create a list of possible routes to take from this intersection then iterate over the
			//list and find the shortest route and return that one
			ArrayList<Hallway> hallwaysContainingStart = new ArrayList<Hallway> ();
			for(Floor f : building.getFloors()){
				for(Hallway h : f.getHallways()){
					if(h.getEntities().contains(start)){
						hallwaysContainingStart.add(h);
					}
				}
			}

			ArrayList<Route> routesForInter = new ArrayList<Route>();
			for(Hallway h : hallwaysContainingStart){
				entities = h.getEntities();
				startIndex = entities.indexOf(start);

				//we are at the start of the hallway
				if(startIndex == 0){
					Route tempRoute = getRoute(entities.get(1), building, route);
					if(tempRoute != null)
						routesForInter.add(tempRoute);
				}
				//we are the end of a hallway
				else if(startIndex == entities.size()-1){
					Route tempRoute = getRoute(entities.get(startIndex-1), building, route);
					if(tempRoute != null)
						routesForInter.add(tempRoute);
				}


				//we are in the middle of a hallway
				else{
					
					Route tempRoute = getRoute(entities.get(startIndex+1), building, route);
					Route tempRoute2 = getRoute(entities.get(startIndex-1), building, route);
					if(tempRoute != null)
						routesForInter.add(tempRoute);
					if(tempRoute2 != null)
						routesForInter.add(tempRoute);
				}
			}

			if(routesForInter.isEmpty())
				return null;
			else{

				int index = 0;
				for(int i = 1; i<routesForInter.size(); i++){
					if(routesForInter.get(i).getTraversedSize()< routesForInter.get(i-1).getTraversedSize()){
						index = i;
					}
				}
				return routesForInter.get(index);
			}
		}




		//start location is an Exit
		/*else if(start instanceof Exit){
			//TODO add GeoPoint of the Exit to directions list for Overlay point to point directions.add()
			route.addDirection(start);

			//we are at the start of the hallway
			if(startIndex == 0)
				return getRoute(entities.get(1), end, building, route);


			//we are the end of a hallway
			else if(startIndex == entities.size()-1)
				return getRoute(entities.get(startIndex-2), end, building, route);


			//we are in the middle of a hallway
			else{

				Route tempRoute = getRoute(entities.get(startIndex+1), end, building, route);
				if(tempRoute == null){ //we already went this direction so go the other way
					return getRoute(entities.get(startIndex-1), end, building, route);
				}
				Route tempRoute2 = getRoute(entities.get(startIndex-1), end, building, route);
				if(tempRoute2 != null && tempRoute.getTraversedSize()< tempRoute2.getTraversedSize()){
					return tempRoute;
				}
				return tempRoute2;
			}
		}*/


		//start location is a Stairwell
		route.addDirection(start);

		Stairwell stair = null;
		int currentFloor = ((Stairwell) start).getCurrentFloor();
		ArrayList<String> floorsWithExits = building.getExitFloors();

		if(!floorsWithExits.contains(currentFloor+""))
			stair = building.containsStairwellsAtLoc(((Stairwell) start).getGeopoint());

		if(stair == null)
			stair = (Stairwell) start;
		else{
			route.addDirection(stair);
			route.addTraversed(stair);
		}

		//go from whatever stairwell we at
		boolean foundStart = false;
		for(Floor f : building.getFloors()){
			for(Hallway h : f.getHallways()){
				if(h.getEntities().contains(stair)){
					entities = h.getEntities();
					startIndex = entities.indexOf(stair);
					foundStart = true;
					break;
				}
			}
			if(foundStart)
				break;
		}

		//we are at the start of the hallway
		if(startIndex == 0)
			return getRoute(entities.get(1), building, route);

		//we are the end of a hallway
		else if(startIndex == entities.size()-1)
			return getRoute(entities.get(startIndex-1), building, route);

		//we are in the middle of a hallway
		else{
			Route tempRoute = getRoute(entities.get(startIndex+1), building, route);
			Route tempRoute2 = getRoute(entities.get(startIndex-1), building, route);

			if(tempRoute2 != null && tempRoute != null && tempRoute.getTraversedSize()< tempRoute2.getTraversedSize())
				return tempRoute;
			if(tempRoute2 != null && tempRoute != null && tempRoute.getTraversedSize()>= tempRoute2.getTraversedSize())
				return tempRoute2;
			if(tempRoute == null && tempRoute2 != null)
				return tempRoute2;
			if(tempRoute != null && tempRoute2 == null)
				return tempRoute;
			else
				return null;

		}
	}

}

